package com.internetCafes.spms.web.sys.controller;

import cn.hutool.core.util.ObjectUtil;
import com.internetCafes.spms.common.CommonConstants;
import com.internetCafes.spms.common.module.sms.SmsAlidayu;
import com.internetCafes.spms.common.utils.IdCardUtils;
import com.internetCafes.spms.common.utils.ShiroUtils;
import com.internetCafes.spms.common.utils.wechat.WechatOpenIdUtil;
import com.internetCafes.spms.core.annotation.SysLog;
import com.internetCafes.spms.core.utils.CharUtil;
import com.internetCafes.spms.core.utils.R;
import com.internetCafes.spms.web.sys.form.SysLoginForm;
import com.internetCafes.spms.web.sys.form.SysRecoverForm;
import com.internetCafes.spms.web.sys.form.SysRegisterForm;
import com.internetCafes.spms.web.sys.model.UserInfo;
import com.internetCafes.spms.web.sys.service.CaptchaInfoService;
import com.internetCafes.spms.web.sys.service.UserInfoService;
import com.internetCafes.spms.web.sys.service.UserTokenInfoService;
import com.internetCafes.spms.web.tenant.model.TenantInfo;
import com.internetCafes.spms.web.tenant.service.TenantInfoService;
import com.sms.common.util.hutool.core.collection.CollectionUtil;
import com.sms.common.util.hutool.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录相关
 *
 * @author Sunny
 * @email rekeeper2011@hotmail.com
 * @date 2016年11月10日 下午1:15:31
 */
@RestController
public class LoginController {

    @Autowired
    private CaptchaInfoService captchaInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserTokenInfoService userTokenInfoService;

    @Autowired
    private TenantInfoService tenantInfoService;

    private static final Logger logger = Logger.getLogger(LoginController.class);

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${spring.profiles.active}")
    private String active;

    @Value("${system.login.isVerifyPassWord}")
    private boolean isVerifyPassWord;

    @Value("${system.login.isVerifyCaptcha}")
    private boolean isVerifyCaptcha;

    @RequestMapping(value = "/sys/sendMobileCaptcha", method = RequestMethod.GET)
    public R sendMobileCaptcha(String mobile) {
        String oldCode = CharUtil.getRandomNum(6);
        String code = SmsAlidayu.sendVerificationCode(mobile, oldCode);
        if (code == null) {
            return R.error();
        }

        redisTemplate.opsForValue().set(mobile, oldCode, 60 * 30, TimeUnit.SECONDS);
        Map<String, Object> params = new HashMap<>();
        params.put("mobile", mobile);
        return R.ok(params);
    }


    @RequestMapping(value = "/sys/sendMobileCaptchaAndCheck", method = RequestMethod.GET)
    public R sendMobileCaptchaAndCheck(String mobile) {
        UserInfo u = ShiroUtils.getUserEntity();
        if (u.getId() == CommonConstants.SUPER_ADMIN) {
            return R.error("管理员不能进行检查");
        }

        if (mobile.equals(u.getName())) {
            return R.error("手机号为当前用户");
        }

        String code = SmsAlidayu.sendVerificationCode(mobile, CharUtil.getRandomNum(6));
        if (code == null) {
            return R.error();
        }

        redisTemplate.opsForValue().set(mobile, code, 60 * 30, TimeUnit.SECONDS);
        Map<String, Object> params = new HashMap<>();
        params.put("mobile", mobile);
        return R.ok(params);
    }


    @RequestMapping(value = "captcha", method = RequestMethod.GET)
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        if (isVerifyCaptcha) {
            captchaJpg(response, uuid);
        }
    }

    @RequestMapping(value = "captcha.jpg", method = RequestMethod.GET)
    public void captchaJpg(HttpServletResponse response, String uuid) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        //获取图片验证码
        BufferedImage image = captchaInfoService.getCaptcha(uuid);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

    /**
     * 登陆时根据用户手机号获取其对应所有公司
     *
     * @param mobile 用户手机号
     * @return 用户所有公司列表
     */
    @PostMapping("/sys/login/getTenantList/{mobile}")
    public List<UserInfo> getTenantList(@PathVariable("mobile") String mobile) {
        return userInfoService.queryByName(mobile);
    }


    /**
     * 登录
     *
     * @author llz
     */
    @SysLog("用户登录")
    @PostMapping("/sys/login")
    public Map<String, Object> login(@RequestBody SysLoginForm loginForm) {
        // 添加登录过滤，如果配置为0 则跳过验证码验证
        if (isVerifyCaptcha) {
            boolean isOk = captchaInfoService.validate(loginForm.getUuid(), loginForm.getCaptcha());
            if (!isOk) {
                return R.error("验证码不正确");
            }
        }
        return doLogin(loginForm);
    }

    /**
     * 登录用户
     *
     * @param loginForm 登录请求参数信息
     * @return 用户登录返回结果
     */
    private R doLogin(SysLoginForm loginForm) {
        UserInfo user;
        if (ObjectUtil.isNull(loginForm.getTenantId())) {
            Map<String, Object> params = new HashMap<>();
            params.put("name", loginForm.getUsername());
            params.put("deptName", loginForm.getOrgName());
            user = userInfoService.queryByOrgNameAndUseName(params);
        } else {
            user = userInfoService.getByTenantIdAndName(loginForm.getTenantId(), loginForm.getUsername());
        }
        if (user == null) {
            return R.error("账号不正确");
        }

        // 添加登录过滤，如果配置为0 则跳过密码验证
        if (isVerifyPassWord) {
            //账号不存在、密码错误
            if (!user.getPassword().equals(new Sha256Hash(loginForm.getPassword(), user.getSalt()).toHex())) {
                return R.error("账号或密码不正确");
            }
        }

        //账号锁定
        if (user.getStatus() == 0) {
            return R.error("账号已被锁定,请联系管理员");
        }

        //生成token，并保存到数据库
        return userTokenInfoService.createToken(user.getId());
    }

    /**
     * 登陆
     *
     * @param username 账号
     * @param password 密码
     * @return 登录成功返回信息
     * @author llz
     */
    private R doLogin(String orgName, String username, String password) {
        Map<String, Object> params = new HashMap<>();
        params.put("name", username);
        params.put("deptName", orgName);
        UserInfo user = userInfoService.queryByOrgNameAndUseName(params);
        if (user == null) {
            return R.error("账号不正确");
        }

        // 添加登录过滤，如果配置为0 则跳过密码验证
        if (isVerifyPassWord) {
            //账号不存在、密码错误
            if (!user.getPassword().equals(new Sha256Hash(password, user.getSalt()).toHex())) {
                return R.error("账号或密码不正确");
            }
        }

        //账号锁定
        if (user.getStatus() == 0) {
            return R.error("账号已被锁定,请联系管理员");
        }

        //生成token，并保存到数据库
        return userTokenInfoService.createToken(user.getId());
    }
//
//    /**
//     * 登录
//     */
//    @SysLog("用户登录")
//    @PostMapping("/sys/login")
//    public Map<String, Object> login(@RequestBody SysLoginForm loginForm) {
//        // 添加登录过滤，如果时开发环境不对验证码进行验证 BY Zj 2021/4/7
//        if (!active.equals("dev")) {
//            boolean isOk = captchaInfoService.validate(loginForm.getUuid(), loginForm.getCaptcha());
//            if (!isOk) {
//                return R.error("验证码不正确");
//            }
//        }
//        return doLogin(loginForm.getOrgName(), loginForm.getUsername(), loginForm.getPassword());
//    }
//
//
//    /**
//     * 登陆
//     *
//     * @param username
//     * @param password
//     * @return
//     */
//    private R doLogin(String orgName, String username, String password) {
//        Map<String, Object> params = new HashMap<>();
//        params.put("name", username);
//        params.put("deptName", orgName);
//        UserInfo user = userInfoService.queryByOrgNameAndUseName(params);
//        if (user == null) {
//            return R.error("账号不正确");
//        }
//
//        // 添加登录过滤，如果时开发环境不对密码进行验证 BY Zj 2021/4/7
//        if (!active.equals("dev")) {
//            //账号不存在、密码错误
//            if (!user.getPassword().equals(new Sha256Hash(password, user.getSalt()).toHex())) {
//                return R.error("账号或密码不正确");
//            }
//        }
//
//        //账号锁定
//        if (user.getStatus() == 0) {
//            return R.error("账号已被锁定,请联系管理员");
//        }
//
//        if (active.equals("dev")) {
//            UserTokenInfo userTokenInfo = userTokenInfoService.queryByUserId(user.getId());
//            if (userTokenInfo != null) {
//                R r = R.ok().put("token", userTokenInfo.getToken()).put("expire", userTokenInfo.getExpireTime());
//                return r;
//            }
//        }
//        //生成token，并保存到数据库
//        return userTokenInfoService.createToken(user.getId());
//    }


    /**
     * 找回密码
     *
     * @return
     */
    @PostMapping(value = "/sys/recover")
    public Map<String, Object> recover(@RequestBody SysRecoverForm recoverForm) {

        if (StringUtils.isBlank(recoverForm.getPassword())) {
            return R.error("请输入密码");
        }

        if (StringUtils.isBlank(recoverForm.getCode())) {
            return R.error("请输入短信验证码");
        }

        String proCode = (String) redisTemplate.opsForValue().get(recoverForm.getMobile());

        if (StringUtils.isBlank(proCode)) {
            return R.error("验证码已失效");
        }

        if (!proCode.equals(recoverForm.getCode())) {
            return R.error("短信验证码不正确");
        }

        Map<String, Object> params = new HashMap<>();
        params.put("name", recoverForm.getMobile());
        params.put("deptName", recoverForm.getOrgName());
        UserInfo u = userInfoService.queryByOrgNameAndUseName(params);

        if (u == null) {
            return R.error("用户不存在，请联系管理员");
        } else {
            String newPassword = new Sha256Hash(recoverForm.getPassword(), u.getSalt()).toHex();
            userInfoService.updatePassword(u.getId(), u.getPassword(), newPassword);
            return doLogin(recoverForm.getOrgName(), recoverForm.getMobile(), recoverForm.getPassword());
        }
    }


    /**
     * 注册
     */
    @RequestMapping(value = "/sys/register", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> register(@RequestBody SysRegisterForm registerForm) {

        String proCode = (String) redisTemplate.opsForValue().get(registerForm.getMobile());

        if (StringUtils.isBlank(proCode)) {
            return R.error("验证码已失效");
        }

        if (!proCode.equals(registerForm.getCode())) {
            return R.error("短信验证码不正确");
        }

        if (!IdCardUtils.isValidSocialCreditCode(registerForm.getCertificateCode())) {
            return R.error("社会统一信用代码已被注册不正确");
        }

        if (StringUtils.isBlank(registerForm.getPassword())) {
            return R.error("请输入密码");
        }

        Map<String, Object> params = new HashMap<>();
        params.put("certificateCode", registerForm.getCertificateCode());
        List<TenantInfo> tenantInfoList = tenantInfoService.query(params);
        if (tenantInfoList != null && tenantInfoList.size() > 0) {
            return R.error("社会统一信用代码已被注册，请勿重复注册");
        }

        params = new HashMap<>();
        params.put("name", registerForm.getMobile());
        params.put("deptName", registerForm.getOrgName());
        UserInfo u = userInfoService.queryByOrgNameAndUseName(params);
        if (u == null) {
            tenantInfoService.save(registerForm);
            return R.ok("注册成功，客服会在2个工作日内与你联系!");
        } else {
            return R.error("手机号已被注册");
        }
    }

    /**
     * 获取openId
     */
    @PostMapping("/wx/sys/openId")
    public R getOpenId(@RequestBody JSONObject code) {
        if (StringUtils.isBlank((String) code.get("code"))) {
            return R.error("code不能为空");
        }
        Map<String, String> oauthMap = WechatOpenIdUtil.getOauthInfo((String) code.get("code"));
        String openId = oauthMap.get("openid");
        if (StringUtils.isBlank(openId) || "null".equals(openId)) {
            logger.warn(code + "根据code获取openid失败，原因：" + oauthMap.get("errcode") + oauthMap.get("errmsg"));
            return R.error("获取openid失败");
        }

        return R.ok().put("openid", openId);
    }

    /**
     * 根据用户名密码登录
     */
    @PostMapping("/wx/sys/loginByOpenId")
    public R loginByOpenId(@RequestBody JSONObject openId) {
        if (StringUtils.isBlank((String) openId.get("openId"))) {
            return R.error("openid不能为空");
        }
        Map<String, Object> params = new HashMap<>(4);
        params.put("openId", openId.get("openId"));
        List<UserInfo> userInfos = userInfoService.queryList(params);
        if (CollectionUtil.isEmpty(userInfos)) {
            return R.error("未绑定");
        }
        UserInfo u = userInfos.get(0);
        R token = userTokenInfoService.createToken(u.getId());

        return R.ok().put("userInfo", u).put("token", token.get("token")).put("expire", token.get("expire"));
    }

    /**
     * 根据用户名密码登录
     */
    @PostMapping("/wx/sys/bindByOpenId")
    public R bindByOpenId(@RequestBody SysLoginForm loginForm) {
        if (StringUtils.isBlank(loginForm.getOpenId())) {
            return R.error("openid不能为空");
        }

        Map<String, Object> params = new HashMap<>(5);
        params.put("name", loginForm.getUsername());
        params.put("deptName", loginForm.getOrgName());
        UserInfo user = userInfoService.queryByOrgNameAndUseName(params);
        if (user == null) {
            return R.error("账号不正确");
        }

        //账号不存在、密码错误
        if (!user.getPassword().equals(new Sha256Hash(loginForm.getPassword(), user.getSalt()).toHex())) {
            return R.error("账号或密码不正确");
        }

        //账号锁定
        if (user.getStatus() == 0) {
            return R.error("账号已被锁定,请联系管理员");
        }

        //如果存在该微信openid已经绑定了其他用户，则修改其用户ID
        params = new HashMap<>(5);
        params.put("openId", loginForm.getOpenId());
        List<UserInfo> userInfos = userInfoService.queryList(params);
        if (CollectionUtil.isNotEmpty(userInfos)) {
            UserInfo userInfo = userInfos.get(0);
            userInfo.setOpenId("");
            userInfoService.justUpdate(userInfo);
        }
        R token = userTokenInfoService.createToken(user.getId());
        user.setOpenId(loginForm.getOpenId());
        userInfoService.justUpdate(user);
        user.setPassword("");
        user.setSalt("");
        return R.ok().put("userInfo", user).put("token", token.get("token")).put("expire", token.get("expire"));
    }

    /**
     * 找回密码
     *
     * @return
     */
    @PostMapping(value = "/wx/sys/recoverPassword")
    public Map<String, Object> recoverPassword(@RequestBody SysRecoverForm recoverForm) {

        if (StringUtils.isBlank(recoverForm.getPassword())) {
            return R.error("请输入密码");
        }

        if (StringUtils.isBlank(recoverForm.getCode())) {
            return R.error("请输入短信验证码");
        }

        String proCode = (String) redisTemplate.opsForValue().get(recoverForm.getMobile());

        if (StringUtils.isBlank(proCode)) {
            return R.error("验证码已失效");
        }

        if (!proCode.equals(recoverForm.getCode())) {
            return R.error("短信验证码不正确");
        }

        Map<String, Object> params = new HashMap<>();
        params.put("name", recoverForm.getMobile());
        params.put("deptName", recoverForm.getOrgName());
        UserInfo u = userInfoService.queryByOrgNameAndUseName(params);

        if (u == null) {
            return R.error("用户不存在，请联系管理员");
        } else {
            String newPassword = new Sha256Hash(recoverForm.getPassword(), u.getSalt()).toHex();
            userInfoService.updatePassword(u.getId(), u.getPassword(), newPassword);
            return R.ok();
        }
    }

    /**
     * 登出
     */
    @PostMapping("/wx/sys/logoutByOpenId")
    public R logoutByOpenId(@RequestBody JSONObject openId) {
        if (StringUtils.isBlank(openId.getStr("openId"))) {
            return R.error("openId不能为空");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("openId", openId.getStr("openId"));
        List<UserInfo> userInfos = userInfoService.queryList(params);
        UserInfo userInfo = userInfos.get(0);
        userInfo.setOpenId("");
        userInfo.setPassword(null);
        userInfoService.update(userInfo);
        return R.ok();
    }

    /**
     * 退出
     */
    @PostMapping("/sys/logout")
    public R logout() {
        userTokenInfoService.logout(ShiroUtils.getUserEntity().getId());
        return R.ok();
    }
}
